home *** CD-ROM | disk | FTP | other *** search
/ Scene 96 / Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso / misc / coding / midas060 / src / dsmmix.asm < prev    next >
Encoding:
Assembly Source File  |  1997-01-16  |  55.1 KB  |  1,780 lines

  1. ;*      DSMMIX.ASM
  2. ;*
  3. ;* Digital Sound Mixer low-level mixing routines
  4. ;*
  5. ;* $Id: dsmmix.asm,v 1.9 1997/01/16 18:41:59 pekangas Exp $
  6. ;*
  7. ;* Copyright 1996,1997 Housemarque Inc.
  8. ;*
  9. ;* This file is part of the MIDAS Sound System, and may only be
  10. ;* used, modified and distributed under the terms of the MIDAS
  11. ;* Sound System license, LICENSE.TXT. By continuing to use,
  12. ;* modify or distribute this file you indicate that you have
  13. ;* read the license and understand and accept it fully.
  14. ;*
  15.  
  16. IDEAL
  17. P386
  18.  
  19. ; Possibly environment dependent code is marked with *!!*
  20.  
  21.  
  22. INCLUDE "lang.inc"
  23. INCLUDE "errors.inc"
  24. INCLUDE "sdevice.inc"
  25. INCLUDE "dsm.inc"
  26. INCLUDE "mglobals.inc"
  27.  
  28. IFNDEF NOEMS
  29. INCLUDE "ems.inc"
  30. ENDIF
  31.  
  32.  
  33.  
  34.  
  35. ;/***************************************************************************\
  36. ;*
  37. ;* Macro:    NumLabel lblname, lblnum
  38. ;*
  39. ;* Description: Creates a numbered label in the source, format _namenum
  40. ;*              (eg. _table1)
  41. ;*
  42. ;* Input:    lblname     name for the label
  43. ;*        lblnum        number for the label
  44. ;*
  45. ;\***************************************************************************/
  46.  
  47. MACRO    NumLabel lblname, lblnum
  48. _&lblname&lblnum:
  49. ENDM
  50.  
  51.  
  52.  
  53. ;/***************************************************************************\
  54. ;*
  55. ;* Macro:    JmpTable lblname, lblcount
  56. ;*
  57. ;* Description: Creates a jump offset table in the source. The table consists
  58. ;*        of near offsets of labels _lblname0 - _lblnameX
  59. ;*
  60. ;* Input:    lblname     name of labels to be used for the table
  61. ;*        lblcount    number of labels
  62. ;*
  63. ;\***************************************************************************/
  64.  
  65. MACRO   defoffs lblname, lblnum
  66. IFDEF __16__
  67.     DW    offset _&lblname&lblnum
  68. ELSE
  69.         DD      offset _&lblname&lblnum
  70. ENDIF
  71. ENDM
  72.  
  73. MACRO    JmpTable lblname, lblcount
  74. numb = 0
  75. REPT    lblcount
  76.         defoffs lblname, %numb
  77. numb = numb + 1
  78. ENDM
  79. ENDM
  80.  
  81.  
  82.  
  83. ;/***************************************************************************\
  84. ;*
  85. ;* Macro:       MixLoop         mname, mixLp, DIinc, counter
  86. ;*
  87. ;* Description: Generates code for inner mixing loop, REPeaTed 16 times.
  88. ;*              Mixing is started with a near call to some label in the
  89. ;*              mixing loop and ends with a near return
  90. ;*
  91. ;* Input:    mname        mixing loop name (ie. m8mna)
  92. ;*        mixLp        macro that contains code for mixing loop
  93. ;*              DIinc           _di increment after each loop (16 times)
  94. ;*        counter     loop counter (ie. cx)
  95. ;*
  96. ;\***************************************************************************/
  97.  
  98. MACRO   MixLoop         mname, mixLp, DIinc, counter
  99. LOCAL    lp
  100.  
  101. LABEL   &mname  _int
  102. JmpTable    &mname, 17
  103.  
  104. lp:
  105. num = 0
  106. REPT    16
  107.     NumLabel &mname, %num
  108.     &mixLp %num
  109.     num = num + 1
  110. ENDM
  111.     NumLabel &mname, %num
  112.  
  113. IF DIinc NE 0
  114.         add     di,DIinc                ; mix next DIInc bytes
  115. ENDIF
  116.     dec    counter
  117.     jnz    lp
  118.     retn
  119.  
  120. ENDM    MixLoop
  121.  
  122.  
  123.  
  124.  
  125.  
  126. DATASEG
  127.  
  128. ; Mixing routine temporary variables: (in data segment for easier access and
  129. ; speed)
  130.  
  131. D_int   lim1 ;FIXME
  132. D_int   lim2
  133.  
  134. D_ptr   sample                  ; pointer to beginning of sample data
  135. D_ptr   chan                    ; pointer to current channel struct
  136. D_int   lpStart                 ; current loop start
  137. D_int   lpEnd                   ; current loop end
  138. D_int   lpType                  ; current loop type
  139. D_int   direction               ; current playing direction
  140. D_int   released                ; sound released flag - 1 if sound has been
  141.                                 ; released but first loop is still being
  142.                                 ; played
  143. D_int   ALEChange               ; 1 if Amiga Loop Emulation sample change
  144.                                 ; is necessary when sample or loop ends
  145. D_int   mixLeft                 ; number of elements left to mix
  146. D_ptr   dest                    ; mixing destination pointer
  147. D_long  incr                    ; sample playing position increment
  148. D_long  maxMix                  ; maximum number of sample bytes that may be
  149.                                 ; mixed during this mixing process
  150. D_int   position                ; sample playing position whole part
  151. D_int   posLow                  ; sample playing position fractional part
  152.                                 ; (only lower 16 bits are used)
  153. D_ptr   mixRout                 ; pointer to mixing routine
  154. IFDEF __16__
  155. D_int   prevPos                 ; position before mixing (required for
  156.                                 ; checking for bidirectional loop start in
  157.                                 ; 16-bit modes under some circumstances)
  158. ENDIF
  159. D_int   mixLoop                 ; pointer to mixing loop start
  160.  
  161. IFDEF __16__
  162. D_int   mixCount                ; mixing counter for 16-bit mixing loops
  163. ENDIF
  164.  
  165. D_int   panning                 ; current channel panning position
  166. D_int   fracIncr                ; mixing position fraction increment in some
  167.                                 ; mixing routines
  168. D_int   chanNum                 ; channel number
  169. D_ptr   loopCallback            ; loop callback function
  170.  
  171. leftVolume      DB      ?       ; left channel volume in smooth panning
  172. rightVolume     DB      ?       ; right channel volume in smooth panning
  173.  
  174.  
  175.  
  176. CODESEG
  177.  
  178.  
  179.  
  180.  
  181. ;/***************************************************************************\
  182. ;*
  183. ;* Function:    int dsmMix(unsigned channel, void *mixRoutine,
  184. ;*                  unsigned volume, unsigned numElems);
  185. ;*
  186. ;* Description: Mixes data for one channel. Used internally by dsmMixData().
  187. ;*
  188. ;* Input:       unsigned channel        channel number
  189. ;*              void *mixRoutine        pointer to low-level mixing routine
  190. ;*              unsigned volume         actual playing volume (volume in
  191. ;*                                      channel structure is ignored)
  192. ;*              unsigned numElems       number of elements to mix (see
  193. ;*                                      dsmMixData())
  194. ;*
  195. ;* Returns:     MIDAS error code
  196. ;*
  197. ;\***************************************************************************/
  198.  
  199. PROC    dsmMix  _funct          channel : _int, mixRoutine : _ptr, \
  200.                                 volume : _int, numElems : _int
  201. USES    _si,_di,_bx
  202.  
  203.         cld
  204.  
  205.         mov     ax,ds
  206. IFDEF __32__
  207.         mov     es,ax
  208. ENDIF
  209. IFDEF __16__
  210.         mov     fs,ax                   ; fs will be used to access variables
  211. ENDIF                                   ; in data segment when ds is destroyed
  212.  
  213.         mov     _ax,[numElems]          ; mixLeft = number of elements left
  214.         mov     [mixLeft],_ax           ; to mix
  215.  
  216.         mov     _ax,[channel]           ; make sure we have channel number
  217.         mov     [chanNum],_ax           ; always accessable
  218.  
  219.         ; Set dest to current mixing position in buffer:
  220.         COPYPTR [dest],[dsmMixBuffer]
  221.  
  222.         ; Point mixRout to mixing routine:
  223.         COPYPTR [mixRout],[mixRoutine]
  224.  
  225.         ; Point _gsbx and chan to current channel structure:
  226.         LOADPTR gs,_bx,[dsmChannels]
  227.         imul    _ax,[channel],SIZE dsmChannel
  228.         add     _bx,_ax
  229.         mov     [_int chan],_bx
  230. IFDEF __16__
  231.         ;*!!*
  232.         mov     [word chan+2],gs
  233. ENDIF
  234.  
  235.         ; Copy loop callback pointer:
  236.         mov     eax,[_gsbx+dsmChannel.loopCallback]
  237.         mov     [loopCallback],eax
  238.  
  239.         ; Check that there is a sample:
  240.         cmp     [_gsbx+dsmChannel.sampleType],smpNone
  241.         je      @@nodata
  242.  
  243.         ; Store current playing direction in direction:
  244.         mov     _ax,[_gsbx+dsmChannel.direction]
  245.         mov     [direction],_ax
  246.  
  247.         ; Copy position whole and fractional parts to internal variables:
  248.         mov     _ax,[_gsbx+dsmChannel.playPos]
  249.         mov     [position],_ax
  250.         mov     _ax,[_gsbx+dsmChannel.playPosLow]
  251.         mov     [posLow],_ax
  252.  
  253.         ; Copy channel panning position
  254.         mov     _ax,[_gsbx+dsmChannel.panning]
  255.         mov     [panning],_ax
  256.  
  257.         ; Calculate sample position increment for each destination element:
  258.         mov     eax,[_gsbx+dsmChannel.rate]     ; playing rate
  259.         mov     edx,eax                 ; eax = sample pos increment =
  260.         shl     eax,16                  ; rate / dsmMixRate
  261.         shr     edx,16
  262. IFDEF __16__
  263.         xor     ecx,ecx
  264. ENDIF
  265.         mov     _cx,[dsmMixRate]        ; (16.16 bit fixed point number)
  266.         div     ecx
  267.     mov    [incr],eax        ; store position increment
  268.  
  269.         ; Calculate maximum number of sample bytes that can be mixed during
  270.         ; the whole mixing process for this channel (used to prevent divide
  271.         ; overflows and speed up some processing):
  272. IFDEF __16__
  273.         xor     eax,eax
  274. ENDIF
  275.         mov     _ax,[numElems]          ; eax = number of elements
  276.         mul     [incr]                  ; multiply with position increment
  277.         shrd    eax,edx,16              ; convert to integer
  278.         add     eax,2                   ; add two for safety and rounding
  279.         mov     [maxMix],eax            ; margin
  280.  
  281.  
  282. @@newsample:    ; ALE logic jumps here if sample is changed
  283.  
  284.         ; Check channel status:
  285.         mov     _ax,[_gsbx+dsmChannel.status]
  286.         cmp     _ax,dsmChanStopped      ; channel stopped?
  287.         je      @@nodata                ; if yes, there is no data to mix
  288.         cmp     _ax,dsmChanEnd          ; channel ended?
  289.         je      @@nodata                ; if yes, there is no data to mix
  290.         cmp     _ax,dsmChanPlaying      ; playing normally?
  291.         je      @@playnorm              ; if yes, use first loop
  292.  
  293.         ; Channel sound has been released. Check if the first loop is still
  294.         ; being played, and if so, mark playing released so that the loop will
  295.         ; be changed when the end of the first loop is reached. Otherwise
  296.         ; just use the second loop:
  297.         cmp     [_gsbx+dsmChannel.loopNum],2
  298.         je      @@loop2
  299.         mov     [released],1            ; change loop when loop end is reached
  300.         jmp     @@loop1                 ; use first loop
  301.  
  302. @@loop2:
  303.         ; Use second loop:
  304.         mov     _ax,[_gsbx+dsmChannel.loop2Start]
  305.         mov     [lpStart],_ax
  306.         mov     _ax,[_gsbx+dsmChannel.loop2End]
  307.         mov     [lpEnd],_ax
  308.         mov     _ax,[_gsbx+dsmChannel.loop2Type]
  309.         mov     [lpType],_ax
  310.         jmp     @@loopok1
  311.  
  312.  
  313. @@playnorm:
  314.         mov     [released],0            ; playing not released
  315.  
  316. @@loop1:
  317.         ; Use first loop:
  318.         mov     _ax,[_gsbx+dsmChannel.loop1Start]
  319.         mov     [lpStart],_ax
  320.         mov     _ax,[_gsbx+dsmChannel.loop1End]
  321.         mov     [lpEnd],_ax
  322.         mov     _ax,[_gsbx+dsmChannel.loop1Type]
  323.         mov     [lpType],_ax
  324.  
  325. @@loopok1:
  326.         ; Check if sample has been changed so that ALE sample changing logic
  327.         ; may have to be used later (sample has been changed and both current
  328.         ; and new samples have Amiga compatible looping):
  329.         cmp     [_gsbx+dsmChannel.sampleChanged],0
  330.         je      @@noalech
  331.         cmp     [_gsbx+dsmChannel.loopMode],sdLoopAmiga
  332.         je      @@1
  333.         cmp     [_gsbx+dsmChannel.loopMode],sdLoopAmigaNone
  334.         jne     @@noalech
  335.  
  336. @@1:
  337.         ; Point _essi to new sample:
  338.         LOADPTR es,_si,[dsmSamples]
  339.         imul    _ax,[_gsbx+dsmChannel.sampleHandle],SIZE dsmSample
  340.         add     _si,_ax
  341.         cmp     [_essi+dsmSample.loopMode],sdLoopAmigaNone
  342.         je      @@alech
  343.         cmp     [_essi+dsmSample.loopMode],sdLoopAmiga
  344.         jne     @@noalech
  345.  
  346. @@alech:
  347.         ; Sample has been changed and both current and new sample have Amiga
  348.         ; compatible looping - Amiga Loop Emulation sample change will occur
  349.         ; if current sample ends or reaches loop end:
  350.         mov     [ALEChange],1
  351.         jmp     @@aleok1
  352.  
  353. @@noalech:
  354.         ; Sample will not be changed:
  355.         mov     [ALEChange],0
  356.  
  357. @@aleok1:
  358.         ; Get sample start address:
  359.         mov     edx,[ebx+dsmChannel.sample]
  360.  
  361.         ; We'll need to divide the sample start address by sample size to
  362.         ; make sample start address and mixing position match:
  363.         mov     _ax,[_gsbx+dsmChannel.sampleType]
  364.         cmp     _ax,smp8bitStereo
  365.         je      @@smp8bitStereo
  366.         cmp     _ax,smp16bitMono
  367.         je      @@smp16bitMono
  368.         cmp     _ax,smp16bitStereo
  369.         je      @@smp16bitStereo
  370.         jmp     @@sampleok
  371.  
  372. @@smp8bitStereo:
  373. @@smp16bitMono:
  374.         shr     edx,1
  375.         jmp     @@sampleok
  376.  
  377. @@smp16bitStereo:
  378.         shr     edx,2
  379.  
  380. @@sampleok:
  381.         mov     [sample],edx
  382.         ; Loop sample:
  383. @@loop:
  384.         cmp     [mixLeft],0             ; better safe than sorry
  385.         je      @@alldone
  386.  
  387.         ; Check if we are really playing a stream:
  388.         cmp     [_gsbx+dsmChannel.sampleHandle],DSM_SMP_STREAM
  389.         jne     @@notstream
  390.  
  391. IFDEF __16__
  392.         xor     eax,eax
  393. ENDIF
  394.         ; Check if we would reach stream write position before the loop end:
  395.         mov     _ax,[_gsbx+dsmChannel.streamWritePos]
  396.         cmp     _ax,[position]
  397.         jb      @@notstream             ; nope
  398.  
  399.         ; Check if we have any data in stream buffer:
  400.         je      @@nodata                ; nothing to do - no data
  401.  
  402.         ; Calculate the number of sample bytes to write position:
  403.         sub     _ax,[position]          ; _ax = number of sample bytes
  404.         mov     edx,eax                 ; edx:eax = number of sample bytes in
  405.         shr     edx,16                  ; 16.16 fixed point format
  406.         shl     eax,16
  407. IFDEF __16__
  408.         xor     ecx,ecx
  409.         mov     cx,[posLow]             ; substract position fractional part
  410.         sub     eax,ecx
  411. ELSE
  412.         sub     eax,[posLow]
  413. ENDIF
  414.         sbb     edx,0
  415.  
  416.         jmp     @@loopset
  417.  
  418.  
  419. @@notstream:
  420.         ; Check current loop type:
  421.         mov     _ax,[lpType]
  422.         cmp     _ax,loopNone
  423.         je      @@noloop
  424.         cmp     _ax,loopUnidir
  425.         je      @@unidir
  426.  
  427.         ; Bidirectional loop, check direction:
  428.         cmp     [direction],-1
  429.         je      @@bdback
  430.  
  431.         ; Bidirectional loop forwards - calculate number of sample bytes to
  432.         ; loop end:
  433. IFDEF __16__
  434.         xor     eax,eax
  435. ENDIF
  436.         mov     _ax,[lpEnd]             ; _ax = number of sample bytes
  437.         sub     _ax,[position]          ; before loop end
  438.         mov     edx,eax                 ; edx:eax = number of sample bytes in
  439.         shr     edx,16                  ; 16.16 fixed point format
  440.         shl     eax,16
  441. IFDEF __16__
  442.         xor     ecx,ecx
  443.         mov     cx,[posLow]             ; substract position fractional part
  444.         sub     eax,ecx
  445. ELSE
  446.         sub     eax,[posLow]
  447. ENDIF
  448.         sbb     edx,0
  449.  
  450.         ; edx:eax now contains number of sample bytes to mix in 16.16
  451.         ; fixed point format before loop end is reached
  452.         jmp     @@loopset
  453.  
  454.  
  455. @@bdback:
  456.         ; Bidirectional loop backwards - calculate number of sample bytes to
  457.         ; loop start:
  458. IFDEF __16__
  459.         xor     eax,eax
  460. ENDIF
  461.         mov     _ax,[position]          ; _ax = number of sample bytes before
  462.         sub     _ax,[lpStart]           ; loop end
  463.         mov     edx,eax                 ; edx:eax = number of sample bytes in
  464.         shr     edx,16                  ; 16.16 fixed point format
  465.         shl     eax,16
  466. IFDEF __16__
  467.         xor     ecx,ecx
  468.         mov     cx,[posLow]             ; add position fractional part
  469.         add     eax,ecx
  470. ELSE
  471.         add     eax,[posLow]
  472. ENDIF
  473.         adc     edx,0
  474.  
  475.         ; edx:eax now contains number of sample bytes to mix in 16.16
  476.         ; fixed point format before loop end is reached
  477.         jmp     @@loopset
  478.  
  479.  
  480. @@unidir:
  481.         ; Unidirectional loop - calculate number of sample bytes to loop end:
  482. IFDEF __16__
  483.         xor     eax,eax
  484. ENDIF
  485.         mov     _ax,[lpEnd]             ; _ax = number of sample bytes
  486.         sub     _ax,[position]          ; before loop end
  487.         mov     edx,eax                 ; edx:eax = number of sample bytes in
  488.         shr     edx,16                  ; 16.16 fixed point format
  489.         shl     eax,16
  490. IFDEF __16__
  491.         xor     ecx,ecx
  492.         mov     cx,[posLow]             ; substract position fractional part
  493.         sub     eax,ecx
  494. ELSE
  495.         sub     eax,[posLow]
  496. ENDIF
  497.         sbb     edx,0
  498.  
  499.         ; edx:eax now contains number of sample bytes to mix in 16.16
  500.         ; fixed point format before loop end is reached
  501.         jmp     @@loopset
  502.  
  503.  
  504. @@noloop:
  505.         ; No loop - calculate number of sample bytes to sample end:
  506. IFDEF __16__
  507.         xor     eax,eax
  508. ENDIF
  509.         mov     _ax,[_gsbx+dsmChannel.sampleLength]     ; _ax = number of
  510.         sub     _ax,[position]          ; sample bytes before sampleloop end
  511.         mov     edx,eax                 ; edx:eax = number of sample bytes in
  512.         shr     edx,16                  ; 16.16 fixed point format
  513.         shl     eax,16
  514. IFDEF __16__
  515.         xor     ecx,ecx
  516.         mov     cx,[posLow]             ; substract position fractional part
  517.         sub     eax,ecx
  518. ELSE
  519.         sub     eax,[posLow]
  520. ENDIF
  521.         sbb     edx,0
  522.  
  523.  
  524. @@loopset:
  525.         ; edx:eax now contains number of sample bytes to mix in 16.16
  526.         ; fixed point format before loop end is reached
  527.  
  528.         ; Check if maxMix (maximum number of sample bytes that can be mixed
  529.         ; now) is below calculated number of bytes. If so, mix all that is
  530.         ; left and exit: (done to prevent divide overflows later)
  531.  
  532.         mov     ecx,[maxMix]            ; ecx = maximum number of sample bytes
  533.         shr     ecx,16
  534.         cmp     ecx,edx                 ; check high word of whole part
  535.         jb      @@mixmax
  536.  
  537.         mov     ecx,[maxMix]
  538.         shl     ecx,16
  539.         cmp     ecx,eax                 ; check low word of whole part
  540.         jb      @@mixmax
  541.  
  542.  
  543.         ; Now calculate the number of destination elements the number of
  544.         ; sample bytes in edx:eax corresponds to: (this still could overflow,
  545.         ; but it only should happen with playing rates over 800kHz if tempo
  546.         ; is above 31bpm or mixing buffers over 1/13th of a second in length)
  547.  
  548.         div     [incr]                  ; eax = edx:eax / increment
  549.         test    edx,edx                 ; if modulus is not zero, one more
  550.         jz      @@nomod                 ; element must be mixed to actually
  551.         inc     eax                     ; reach loop end
  552.  
  553. @@nomod:
  554. IFDEF __16__
  555.         cmp     eax,0FFFFh              ; limit to 65535 elements (just to
  556.         jb      @@eaxok                 ; make sure there is no unwanted
  557.         mov     eax,0FFFFh              ; truncation)
  558. @@eaxok:
  559. ENDIF
  560.  
  561.         cmp     _ax,[mixLeft]           ; do not mix more elements than there
  562.         jbe     @@mixlset               ; is left to do for this mixing
  563.         mov     _ax,[mixLeft]           ; process
  564.         jmp     @@mixlset
  565.  
  566.  
  567. @@mixmax:
  568.         ; The number of sample bytes to sample/loop end is less than the
  569.         ; maximum number of sample bytes that can be mixed during the whole
  570.         ; mixing process - do all remaining destination elements:
  571.         mov     _ax,[mixLeft]
  572.  
  573. @@mixlset:
  574.         ; eax = number of destination elements to mix
  575.         sub     [mixLeft],_ax           ; decrease number of elements left
  576.  
  577.         cmp     [volume],0              ; is volume zero?
  578.         je      @@zerovol               ; if so, just advance mixing position
  579.  
  580.         ; Call the actual low-level mixing routine:
  581.         PUSHSEGREG gs
  582.         push    _bx
  583.         push    _bp
  584.  
  585. IFDEF __16__
  586.         ; In 16-bit modes store position before mixing so that it can be used
  587.         ; for checking for bidirectional loop start. This is necessary as the
  588.         ; playing position can wrap if the loop start is at the very start of
  589.         ; the sample and there would be no way of knowing if this happened.
  590.         ; In 32-bit modes wrapping is also possible, but it would only cause
  591.         ; problems with loops longer than 2 gigabytes.
  592.         mov     _dx,[position]
  593.         mov     [prevPos],_dx
  594. ENDIF
  595.  
  596.         LOADPTR gs,_si,[sample]         ; point _gssi to sample
  597.         add     _si,[position]          ; point _gssi to current mixing pos.
  598.         mov     bl,[byte channel]       ; bl = channel number
  599.         mov     bh,[byte volume]        ; bh = volume
  600.         mov     _bp,[posLow]            ; _bp = mixing position fract. part
  601.         mov     edx,[incr]              ; edx = mixing position increment
  602.         mov     _cx,_ax                 ; _cx = number of elements to mix
  603.         mov     _di,[_int dest]         ; _di points to mixing destination
  604.  
  605.         cmp     [direction],-1          ; playing backwards?
  606.         jne     @@noback                ; if yes, negate direction
  607.         neg     edx
  608.  
  609. @@noback:
  610.         ; Mix the sound: (we can't do call [mixRout] as it would confuse
  611.         ; the wdisasm/gasm procedure we use to convert this to Linux)
  612.         mov     eax,[mixRout]
  613.         call    eax
  614. ;        call    [mixRout]               ; mix the sound!
  615.  
  616.         mov     [posLow],_bp            ; store new position fractional part
  617.         sub     _si,[_int sample]
  618.         mov     [position],_si          ; store new position whole part
  619.         mov     [_int dest],_di         ; store new mixing destination pos.
  620.  
  621.         pop     _bp
  622.         pop     _bx
  623.         POPSEGREG gs
  624.  
  625.         jmp     @@mixdone
  626.  
  627.  
  628. @@zerovol:
  629.         ; Zero volume - just update mixing position: (eax = number of
  630.         ; destination elements to mix)
  631.  
  632.         mov     _cx,_ax                 ; _cx = number of dest. elements
  633.         mov     edx,[incr]              ; edx = position increment
  634.         cmp     [direction],-1          ; playing backwards?
  635.         jne     @@zvfwd
  636.         neg     edx                     ; if yes, negate direction
  637. @@zvfwd:
  638.         imul    edx
  639.  
  640.         ; edx:eax is now the number of sample bytes "mixed" - add it to
  641.         ; sample playing position: (could use some optimization and thinking)
  642. IFDEF __16__
  643.         mov     edx,eax
  644.         sar     eax,16                  ; update position (number of sample
  645.         add     [posLow],ax             ; bytes mixed always fits in 16 bits)
  646.         adc     [position],dx
  647. ELSE
  648.         mov     esi,[position]
  649.         mov     edi,esi                 ; edi:esi is current playing position
  650.         shl     esi,16                  ; in 16.16 fixed point format
  651.         sar     edi,16
  652.         mov     si,[word posLow]
  653.  
  654.         add     esi,eax                 ; update position in edi:esi
  655.         adc     edi,edx
  656.  
  657.         mov     [word posLow],si        ; set new position fractional part
  658.  
  659.         shr     esi,16
  660.         shl     edi,16                  ; set new position whole part
  661.         or      esi,edi
  662.         mov     [position],esi
  663. ENDIF
  664.  
  665.         cmp     [channel],0             ; is this the first channel?
  666.         jne     @@mixdone               ; if not, mixing is done
  667.  
  668.         ; First channel - clear mixing buffer for this area:
  669.         ; (_cx still contains number of elements)
  670.         PUSHSEGREG ds
  671.         push    _bx
  672.         LOADPTR ds,_di,[dest]
  673.         call    Clear
  674.         mov     [_int dest],_di
  675.         pop     _bx
  676.         POPSEGREG ds
  677.  
  678.  
  679.  
  680. @@mixdone:
  681.         ; Mixing is finished. Sample end or loop end might have been reached
  682.         ; or we might simply have mixed all elements for this process. Check
  683.         ; what is the case and proceed accordingly:
  684.  
  685.         cmp     [lpType],loopNone       ; is there no loop? if so, just check
  686.         je      @@checksmpend           ; if sample end was reached
  687.  
  688.         cmp     [direction],-1          ; going backwards? If so, check if
  689.         je      @@backwards             ; loop start was reached
  690.  
  691.         ; Mixing forward and there is a loop - check if we reached loop end:
  692.         mov     _ax,[position]          ; is position below loop end?
  693.         cmp     _ax,[lpEnd]             ; if is, all mixing is done
  694.         jae     @@loopend
  695.  
  696.         ; We didn't, but if we were playing a stream we might have reached
  697.         ; stream write position - just loop then to make sure:
  698.         cmp     [_esbx+dsmChannel.sampleHandle],DSM_SMP_STREAM
  699.         jne     @@alldone
  700.         jmp     @@loop
  701.  
  702. @@loopend:
  703.         ; Loop end was reached. Check if we should call the callback:
  704.         cmp     [loopCallback],0
  705.         je      @@noloopcb1
  706.  
  707.         ; Call it!
  708.         ; Again, avoid GNU asm confusion:
  709.         mov     eax,[loopCallback]
  710.         call    eax LANG, [channel]
  711. ;        call    [_ptr loopCallback] LANG, [channel]
  712.  
  713. @@noloopcb1:
  714.         ; Check if ALE sample change is necessary:
  715.         cmp     [ALEChange],1
  716.         je      @@alechange
  717.  
  718.         ; ALE sample change not needed. Check if sound has been released and
  719.         ; we should change to second loop:
  720.         cmp     [released],1
  721.         je      @@released
  722.  
  723.         ; None of the above. Check loop type:
  724.         cmp     [lpType],loopUnidir
  725.         je      @@unidirend
  726.  
  727.  
  728.         ; Bidirectional loop end reached - start playing backwards and set
  729.         ; position to lpEnd - (position - lpEnd) = 2*lpEnd - position
  730.         mov     [direction],-1
  731.  
  732. IFDEF __16__
  733.         mov     ax,[lpEnd]              ; edx = eax = lpEnd in 16.16 fixed
  734.         shl     eax,16                  ; point format
  735.         mov     edx,eax
  736.         mov     si,[position]           ; esi = position in 16.16 fixed point
  737.         shl     esi,16                  ; format
  738.         mov     si,[posLow]
  739.         sub     eax,esi                 ; eax = lpEnd - (position - lpEnd)
  740.         add     eax,edx
  741.  
  742.         mov     [posLow],ax             ; store new position
  743.         shr     eax,16
  744.         mov     [position],ax
  745. ELSE
  746.         mov     esi,[lpEnd]
  747.         mov     edi,esi                 ; edi:esi = lpEnd in 16.16 fixed
  748.         shl     esi,16                  ; point format
  749.         shr     edi,16
  750.  
  751.         add     esi,esi                 ; edi:esi = 2*lpEnd
  752.         adc     edi,edi
  753.  
  754.         mov     edx,eax                 ; edx:eax = position in 16.16 fixed
  755.         shl     eax,16                  ; point format
  756.         sar     edx,16
  757.         mov     ax,[word posLow]
  758.  
  759.         sub     esi,eax                 ; edi:esi = 2*lpEnd - position
  760.         sbb     edi,edx
  761.  
  762.         mov     [word posLow],si
  763.         shr     esi,16                  ; store new position
  764.         shl     edi,16
  765.         or      esi,edi
  766.         mov     [position],esi
  767. ENDIF
  768.         jmp     @@checkend
  769.  
  770.  
  771. @@unidirend:
  772.         ; Unidirectional loop end reached - substract loop length from
  773.         ; playing position:
  774.         mov     _ax,[lpEnd]
  775.         sub     _ax,[lpStart]
  776.         sub     [position],_ax
  777.         jmp     @@checkend
  778.  
  779.  
  780. @@backwards:
  781.         ; Playing backwards - check if we reached bidirectional loop start:
  782. IFDEF __32__
  783.         ; 32-bit mode - just check if playing position is below loop start
  784.         ; position: (Use signed comparison to take care of possible wrapping,
  785.         ; so that it won't cause any problems unless the loop is over 2
  786.         ; gigabytes long)
  787.         mov     _ax,[position]          ; if position is above or equal to
  788.         cmp     _ax,[lpStart]           ; loop start, all mixing is done
  789.         jge     @@alldone
  790. ELSE
  791.         ; 16-bit mode - the check above must be done unsigned, and therefore
  792.         ; we also need to check if the playing position after mixing is above
  793.         ; that of before. In that case the position has wrapped and we have
  794.         ; reached loop start:
  795.         mov     _ax,[position]
  796.         cmp     _ax,[prevPos]           ; has position wrapped?
  797.         ja      @@bdlpstart             ; if yes, we are at loop start
  798.  
  799.         cmp     _ax,[lpStart]           ; if position is above or equal to
  800.         jae     @@alldone               ; loop start, all mixing is done
  801.  
  802. @@bdlpstart:
  803. ENDIF
  804.         ; Bidirectional loop start has been reached. Check if we should call
  805.         ; the callback:
  806.         cmp     [loopCallback],0
  807.         je      @@noloopcb2
  808.  
  809.         ; Call it!
  810.         ; GNU asm fix
  811.         mov     eax,[loopCallback]
  812.         call    eax LANG, [channel]
  813. ;        call    [_ptr loopCallback] LANG, [channel]
  814.  
  815. @@noloopcb2:
  816.         ; Change direction and
  817.         ; set new position to (lpStart-position) + lpStart
  818.         mov     [direction],1
  819. IFDEF __16__
  820.         mov     si,[lpStart]            ; esi = lpStart in 16.16 fixed point
  821.         shl     esi,16                  ; format
  822.         shl     eax,16                  ; eax = position in 16.16 fixed point
  823.         mov     ax,[posLow]             ; format
  824.         mov     edx,esi
  825.         sub     esi,eax                 ; esi = lpStart - position + lpStart
  826.         add     esi,edx
  827.  
  828.         mov     [posLow],si             ; store new position
  829.         shr     esi,16
  830.         mov     [position],si
  831. ELSE
  832.         mov     esi,[lpStart]
  833.         mov     edi,esi                 ; edi:esi = lpStart in 16.16 fixed
  834.         shl     esi,16                  ; point format
  835.         shr     edi,16
  836.  
  837.         add     esi,esi                 ; edi:esi = lpStart*2
  838.         adc     edi,edi                 ; (a - b + a = 2a - b)
  839.  
  840.         mov     edx,eax                 ; edx:eax = position in 16.16 fixed
  841.         shl     eax,16                  ; point format
  842.         sar     edx,16
  843.         mov     ax,[word posLow]
  844.  
  845.         sub     esi,eax                 ; edi:esi = lpStart - position +
  846.         sbb     edi,edx                 ;  lpStart = 2*lpStart - position
  847.  
  848.         mov     [word posLow],si
  849.         shr     esi,16                  ; store new position
  850.         shl     edi,16
  851.         or      esi,edi
  852.         mov     [position],esi
  853. ENDIF
  854.         jmp     @@checkend
  855.  
  856.  
  857. @@checksmpend:
  858.         ; No loop - check if sample end has been reached:
  859.         mov     _ax,[position]                          ; position below
  860.         cmp     _ax,[_gsbx+dsmChannel.sampleLength]     ; sample end? if not,
  861.         jb      @@alldone                               ; all mixing is done
  862.  
  863.         ; Sample end reached. Check if ALE sample changing is necessary:
  864.         cmp     [ALEChange],1
  865.         je      @@alechange
  866.  
  867.         ; ALE sample changing not necessary - sample has ended:
  868.         mov     [_gsbx+dsmChannel.status],dsmChanEnd
  869.         jmp     @@nodata
  870.  
  871.  
  872. @@checkend:
  873.         ; Loop end/start succesfully handled. Check if there is more data
  874.         ; to mix, and if not, exit
  875.         cmp     [mixLeft],0
  876.         je      @@alldone
  877.         jmp     @@loop                  ; loop sample
  878.  
  879.  
  880. @@alechange:
  881.         ; Loop end or sample end has been reached and new sample has to be
  882.         ; taken into use (ALE logic):
  883.         PUSHSEGREG gs
  884.         push    _bx
  885.         call    dsmChangeSample LANG, [channel]
  886.         pop     _bx
  887.         POPSEGREG gs
  888.         test    _ax,_ax
  889.         jnz     @@err
  890.  
  891.         ; If new sample is looping start playing from loop start, otherwise
  892.         ; stop playing:
  893.         cmp     [_gsbx+dsmChannel.loopMode],sdLoopAmiga
  894.         jne     @@alenol
  895.  
  896.         ; Start playing from sample loop start:
  897.         mov     _ax,[_gsbx+dsmChannel.loop1Start]
  898.         mov     [position],_ax
  899.         mov     [posLow],0
  900.         jmp     @@newsample
  901.  
  902. @@alenol:
  903.         ; stop playing:
  904.         mov     [_gsbx+dsmChannel.status],dsmChanEnd
  905.         jmp     @@nodata
  906.  
  907.  
  908. @@released:
  909.         ; Sound had been released, but loop had not been changed yet. Now when
  910.         ; we have reached first loop end set values for second loop and
  911.         ; continue playing:
  912.  
  913.         mov     [_gsbx+dsmChannel.loopNum],2    ; playing second loop
  914.         mov     [released],0                    ; sound releasing handled
  915.         mov     _ax,[_gsbx+dsmChannel.loop2Start]
  916.         mov     [lpStart],_ax
  917.         mov     _ax,[_gsbx+dsmChannel.loop2End]
  918.         mov     [lpEnd],_ax
  919.         mov     _ax,[_gsbx+dsmChannel.loop2Type]
  920.         mov     [lpType],_ax
  921.  
  922.         jmp     @@loop
  923.  
  924.  
  925.  
  926. @@nodata:
  927.         ; No more data to be mixed - if this is the first channel clear
  928.         ; the rest of the mixing buffer, otherwise we are done:
  929.         cmp     [channel],0
  930.         jne     @@alldone
  931.  
  932.         ; Clear the rest of the mixing buffer:
  933.         PUSHSEGREG ds
  934.         push    _bx
  935.         mov     _cx,[mixLeft]
  936.         LOADPTR ds,_di,[dest]
  937.         call    Clear
  938.         pop     _bx
  939.         POPSEGREG ds
  940.  
  941.  
  942. @@alldone:
  943.         ; All mixing done - save new mixing position and direction:
  944.         mov     _ax,[position]
  945.         mov     [_gsbx+dsmChannel.playPos],_ax
  946.         mov     _ax,[posLow]
  947.         mov     [_gsbx+dsmChannel.playPosLow],_ax
  948.         mov     _ax,[direction]
  949.         mov     [_gsbx+dsmChannel.direction],_ax
  950.  
  951. @@ok:
  952.         xor     _ax,_ax
  953.         jmp     @@done
  954.  
  955. @@err:
  956.         ERROR   ID_dsmMix
  957.  
  958. @@done:
  959.         ret
  960. ENDP
  961.  
  962.  
  963.  
  964.  
  965. IFDEF __16__
  966.  
  967. ; mono mixing routine: (16-bit)
  968. MACRO   _mono   num
  969.         mov     bl,[gs:si]              ; take byte from source
  970.         add     bp,cx                   ; increment sample position fraction
  971.         mov     ax,[ebx+ebx]            ; take correct value from volume tbl
  972.         adc     si,dx                   ; increment sample position whole part
  973.         add     [di+2*num],ax           ; add word into buffer
  974. ENDM
  975. MixLoop mono, _mono, 32, [fs:mixCount]
  976.  
  977. ELSE
  978.  
  979. ; mono mixing routine: (32-bit)
  980. MACRO   _mono   num
  981.         mov     bl,[esi]                ; take byte from source
  982.         add     ebp,ecx                 ; increment sample position fraction
  983.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  984.         adc     esi,edx                 ; increment sample position whole part
  985.         add     [edi+4*num],eax         ; add word into buffer
  986. ENDM
  987. MixLoop mono, _mono, 64, bp
  988.  
  989. ENDIF
  990.  
  991.  
  992. IFDEF __16__
  993.  
  994. ; mono mixing routine, first channel: (16-bit)
  995. MACRO   _monom  num
  996.     mov    bl,[gs:si]        ; take byte from source
  997.         add     bp,cx                   ; increment sample position fraction
  998.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  999.         adc     si,dx                   ; increment sample position whole part
  1000.         mov     [di+2*num],ax           ; write word into buffer
  1001. ENDM
  1002. MixLoop monom, _monom, 32, [fs:mixCount]
  1003.  
  1004. ELSE
  1005.  
  1006. ; mono mixing routine, first channel: (32-bit)
  1007. MACRO   _monom  num
  1008.         mov     bl,[esi]                ; take byte from source
  1009.         add     ebp,ecx                 ; increment sample position fraction
  1010.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1011.         adc     esi,edx                 ; increment sample position whole part
  1012.         mov     [edi+4*num],eax         ; write word into buffer
  1013. ENDM
  1014. MixLoop monom, _monom, 64, bp
  1015.  
  1016. ENDIF
  1017.  
  1018.  
  1019.  
  1020.  
  1021. ;/***************************************************************************\
  1022. ;*
  1023. ;* Function:    dsmMix8bitMonoMono
  1024. ;*
  1025. ;* Description: Mixing routine for 8-bit mono samples to mono output
  1026. ;*
  1027. ;* Input:       gs              sample data segment (16-bit only)
  1028. ;*              _si             sample mixing position whole part, from the
  1029. ;*                              beginning of the sample segment
  1030. ;*              _bp             sample position fractional part, only lower
  1031. ;*                              16 bits used
  1032. ;*        edx        sample mixing position increment for each
  1033. ;*                destination byte, 16.16 fixed point format
  1034. ;*              _di             pointer to mixing buffer (assumed to be in
  1035. ;*                              the volume table segment)
  1036. ;*              _cx             number of destination elements to mix
  1037. ;*              bh              volume to be used
  1038. ;*              bl              current channel number
  1039. ;*              [ds:panning]    channel panning position
  1040. ;*
  1041. ;* Returns:     _si._bp         new mixing position (same format as input)
  1042. ;*              _di             new destination position
  1043. ;*
  1044. ;* Destroys:    eax, ebx, ecx, edx, esi, edi
  1045. ;*
  1046. ;\***************************************************************************/
  1047.  
  1048. PROC    dsmMix8bitMonoMono      _funct
  1049.  
  1050.         test    _cx,_cx                 ; don't mix zero bytes
  1051.     jz    @@done
  1052.  
  1053.         test    bl,bl                   ; first channel?
  1054.         jne     @@notfirst
  1055.         mov     [mixLoop],offset monom  ; first channel - move to buffer
  1056.         jmp     @@mlok
  1057.  
  1058. @@notfirst:
  1059.         mov     [mixLoop],offset mono   ; not the first channel - add to buf.
  1060.  
  1061. @@mlok:
  1062.         call    MixMono
  1063.  
  1064. @@done:
  1065.         ret
  1066. ENDP
  1067.  
  1068.  
  1069.  
  1070.  
  1071. ;/***************************************************************************\
  1072. ;*
  1073. ;* Function:    void MixMono(void)
  1074. ;*
  1075. ;* Description: Common code for all mono mixing routines.
  1076. ;*
  1077. ;\***************************************************************************/
  1078.  
  1079. PROC    MixMono         _funct
  1080.  
  1081.         add     bh,VOLADD               ; convert volume rounding up
  1082.         shr     bh,VOLSHIFT
  1083.         mov     al,bh
  1084.         xor     ebx,ebx                 ; bh contains volume and bl sample
  1085.         mov     bh,al
  1086.  
  1087.         mov     eax,[dsmVolumeTable]    ; add volume table offset / 4 to
  1088.         shr     eax,2                   ; ebx in 32-bit modes
  1089.         add     ebx,eax
  1090.  
  1091.         mov     eax,ecx                 ; eax = number of elements to mix
  1092.         and     eax,15                  ; in the first loop
  1093.  
  1094.         shl     eax,2
  1095.         neg     eax                     ; eax = jump table offset (64 - 4*eax)
  1096.         add     eax,64
  1097.  
  1098.         sub     edi,eax                 ; undo edi incrementing in loop
  1099.         add     eax,[mixLoop]
  1100.         mov     eax,[eax]
  1101.  
  1102.         shr     ecx,4                   ; ecx = number of loops to mix
  1103.         inc     ecx
  1104.  
  1105.         shl     ebp,16                  ; set position whole part to ebp
  1106.                                         ; upper word
  1107.         mov     bp,cx                   ; set loop counter to bp
  1108.  
  1109.         mov     ecx,edx                 ; ecx = mixing position increment
  1110.         shl     ecx,16                  ; fractional part
  1111.         sar     edx,16                  ; edx = increment whole part
  1112.  
  1113.         call    eax                     ; call the mixing routine
  1114.  
  1115.         shr     ebp,16                  ; restore position fractional part
  1116.                                         ; to ebp lower 16 bits
  1117. @@done:
  1118.     ret
  1119. ENDP
  1120.  
  1121.  
  1122.  
  1123.  
  1124. ; left mixing routine: (32-bit)
  1125. MACRO   _left   num
  1126.         mov     bl,[esi]                ; take byte from source
  1127.         add     ebp,ecx                 ; increment sample position fraction
  1128.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1129.         adc     esi,edx                 ; increment sample position whole part
  1130.         add     [edi+8*num],eax         ; add word into buffer
  1131. ENDM
  1132. MixLoop left, _left, 128, bp
  1133.  
  1134.  
  1135. ; right mixing routine: (32-bit)
  1136. MACRO   _right  num
  1137.         mov     bl,[esi]                ; take byte from source
  1138.         add     ebp,ecx                 ; increment sample position fraction
  1139.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1140.         adc     esi,edx                 ; increment sample position whole part
  1141.         add     [edi+8*num+4],eax       ; add word into buffer
  1142. ENDM
  1143. MixLoop right, _right, 128, bp
  1144.  
  1145.  
  1146. ; middle mixing routine: (32-bit)
  1147. MACRO   _middle num
  1148.         mov     bl,[esi]                ; take byte from source
  1149.         add     ebp,ecx                 ; increment sample position fraction
  1150.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1151.         adc     esi,edx                 ; increment sample position whole part
  1152.         add     [edi+8*num],eax         ; add word to left channel
  1153.         add     [edi+8*num+4],eax       ; add word to right channel
  1154. ENDM
  1155. MixLoop middle, _middle, 128, bp
  1156.  
  1157.  
  1158. ; right mixing routine: (32-bit)
  1159. MACRO   _surround num
  1160.         mov     bl,[esi]                ; take byte from source
  1161.         add     ebp,ecx                 ; increment sample position fraction
  1162.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1163.         adc     esi,edx                 ; increment sample position whole part
  1164.         add     [edi+8*num],eax         ; add word to left channel
  1165.         sub     [edi+8*num+4],eax       ; add word to right channel
  1166. ENDM
  1167. MixLoop surround, _surround, 128, bp
  1168.  
  1169.  
  1170. ; smooth panning mixing routine: (32-bit) (S-L-O-W)
  1171. MACRO   _smooth num
  1172.         mov     bl,[esi]                ; take byte from source
  1173.         add     ebp,[fracIncr]          ; increment sample position fraction
  1174.         mov     cl,bl
  1175.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1176.         adc     esi,edx                 ; increment sample position whole part
  1177.         add     [edi+8*num],eax         ; add word to left channel
  1178.         mov     eax,[4*ecx]
  1179.         add     [edi+8*num+4],eax       ; add word to right channel
  1180. ENDM
  1181. MixLoop smooth, _smooth, 128, bp
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187. ;/***************************************************************************\
  1188. ;*
  1189. ;* Function:    void dsmMix8bitMonoStereo(void)
  1190. ;*
  1191. ;* Description: Mixing routine for 8-bit mono samples to stereomono output
  1192. ;*              See dsmMix8bitMonoMono() for input/output documentation.
  1193. ;*
  1194. ;\***************************************************************************/
  1195.  
  1196. PROC    dsmMix8bitMonoStereo    _funct
  1197.  
  1198. @@ook:
  1199.         test    _cx,_cx                 ; don't mix zero bytes
  1200.     jz    @@done
  1201.  
  1202.         test    bl,bl                   ; first channel?
  1203.         jne     @@notfirst
  1204.  
  1205.         ; This is the first channel - first clear the destination area
  1206.         push    _di _cx
  1207.         shl     ecx,1
  1208.         xor     eax,eax
  1209.         rep     stosd
  1210.         pop     _cx _di
  1211.  
  1212. @@notfirst:
  1213.         ; Check the channel panning position to determine which mixing
  1214.         ; routine to use: (plus the smooth panning routine requires some
  1215.         ; extra work here)
  1216.         mov     _ax,[panning]
  1217.         cmp     _ax,panLeft
  1218.         je      @@left
  1219.         cmp     _ax,panRight
  1220.         je      @@right
  1221.         cmp     _ax,panMiddle
  1222.         je      @@middle
  1223.         cmp     _ax,panSurround
  1224.         je      @@surround
  1225.  
  1226.         ; Smooth panning
  1227.         mov     [mixLoop],offset smooth         ; use smooth panning routine
  1228.  
  1229.         call    MixStereo
  1230.         jmp     @@done
  1231.  
  1232.  
  1233. @@left:
  1234.         mov     [mixLoop],offset left
  1235.         jmp     @@mlok
  1236.  
  1237. @@right:
  1238.         mov     [mixLoop],offset right
  1239.         jmp     @@mlok
  1240.  
  1241. @@middle:
  1242.         mov     [mixLoop],offset middle
  1243.         jmp     @@mlok
  1244.  
  1245. @@surround:
  1246.         mov     [mixLoop],offset surround
  1247.         jmp     @@mlok
  1248.  
  1249.  
  1250. @@mlok:
  1251.         ; Build correct value to ebx:
  1252.         add     bh,VOLADD               ; convert volume rounding up
  1253.         shr     bh,VOLSHIFT
  1254.         and     ebx,0000FF00h           ; bh contains volume and bl sample
  1255.  
  1256.         mov     eax,[dsmVolumeTable]    ; add volume table offset / 4 to
  1257.         shr     eax,2                   ; ebx in 32-bit modes
  1258.         add     ebx,eax
  1259.  
  1260.         mov     eax,ecx                 ; eax = number of elements to mix
  1261.         and     eax,15                  ; in the first loop
  1262.  
  1263.         shl     eax,2
  1264.         neg     eax                     ; eax = jump table offset (64 - 4*eax)
  1265.         add     eax,64
  1266.  
  1267.         sub     edi,eax                 ; undo edi incrementing in loop
  1268.         sub     edi,eax
  1269.         add     eax,[mixLoop]
  1270.         mov     eax,[eax]
  1271.  
  1272.         shr     ecx,4                   ; ecx = number of loops to mix
  1273.         inc     ecx
  1274.  
  1275.         shl     ebp,16                  ; set position whole part to ebp
  1276.                                         ; upper word
  1277.         mov     bp,cx                   ; set loop counter to bp
  1278.  
  1279.         mov     ecx,edx                 ; ecx = mixing position increment
  1280.         shl     ecx,16                  ; fractional part
  1281.         sar     edx,16                  ; edx = increment whole part
  1282.  
  1283.         call    eax                     ; call the mixing routine
  1284.  
  1285.         shr     ebp,16                  ; restore position fractional part
  1286.                                         ; to ebp lower 16 bits
  1287. @@done:
  1288.     ret
  1289. ENDP
  1290.  
  1291.  
  1292.  
  1293.  
  1294. ;/***************************************************************************\
  1295. ;*
  1296. ;* Function:    void MixStereo(void)
  1297. ;*
  1298. ;* Description: Common code for all stereo mixing routines (smooth panning
  1299. ;*              ones)
  1300. ;*
  1301. ;\***************************************************************************/
  1302.  
  1303. PROC    MixStereo       _funct
  1304.  
  1305.         ; Calculate the volumes for left and right channels
  1306.  
  1307.         mov     bl,[byte panning]
  1308.         mov     al,bh
  1309.         test    bl,bl
  1310.         jns     @@spright
  1311.  
  1312.         ; Panning is < 0 (left) - set left channel volume to full value and
  1313.         ; right to volume * (64+panning) / 64:
  1314.         mov     [leftVolume],al
  1315.         add     bl,64
  1316.         mul     bl
  1317.         shr     _ax,6
  1318.         mov     [rightVolume],al
  1319.         jmp     @@spvol
  1320.  
  1321. @@spright:
  1322.         ; Panning is > 0 (right) - set right channel volume to full value and
  1323.         ; left to volume * (64-panning) / 64:
  1324.         mov     [rightVolume],al
  1325.         neg     bl
  1326.         add     bl,64
  1327.         mul     bl
  1328.         shr     _ax,6
  1329.         mov     [leftVolume],al
  1330.  
  1331. @@spvol:
  1332.         ; Write mixing position fractional part increment to [fracIncr]:
  1333.         mov     eax,edx
  1334.         shl     eax,16
  1335.         mov     [fracIncr],eax
  1336.  
  1337.         mov     eax,ecx                 ; eax = number of elements to mix
  1338.         and     eax,15                  ; in the first loop
  1339.  
  1340.         shl     eax,2
  1341.         neg     eax                     ; eax = jump table offset (64 - 4*eax)
  1342.         add     eax,64
  1343.  
  1344.         sub     edi,eax                 ; undo edi incrementing in loop
  1345.         sub     edi,eax
  1346.         add     eax,[mixLoop]
  1347.         mov     eax,[eax]
  1348.  
  1349.         shr     ecx,4                   ; ecx = number of loops to mix
  1350.         inc     ecx
  1351.  
  1352.         shl     ebp,16                  ; set position whole part to ebp
  1353.                                         ; upper word
  1354.         mov     bp,cx                   ; set loop counter to bp
  1355.  
  1356.         sar     edx,16                  ; edx = increment whole part
  1357.  
  1358.         push    eax
  1359.  
  1360.         ; Set ebx to left channel volume * 256
  1361.         mov     bh,[leftVolume]
  1362.         add     bh,VOLADD               ; convert volume rounding up
  1363.         shr     bh,VOLSHIFT
  1364.         and     ebx,0000FF00h           ; bh contains volume and bl sample
  1365.  
  1366.         mov     eax,[dsmVolumeTable]
  1367.         shr     eax,2
  1368.         add     ebx,eax
  1369.  
  1370.         ; Set ecx to right channel volume * 256
  1371.         mov     ch,[rightVolume]
  1372.         add     ch,VOLADD               ; convert volume rounding up
  1373.         shr     ch,VOLSHIFT
  1374.         and     ecx,0000FF00h           ; ch contains volume and cl sample
  1375.  
  1376.         add     ecx,eax
  1377.  
  1378.         pop     eax
  1379.  
  1380.         call    eax                     ; call the mixing routine
  1381.  
  1382.         shr     ebp,16                  ; restore position fractional part
  1383.                                         ; to ebp lower 16 bits
  1384.  
  1385.         ret
  1386. ENDP
  1387.  
  1388.  
  1389.  
  1390. ; 8-bit stereo => mono mixing routine: (32-bit) (S-L-O-W)
  1391. MACRO   _m8stmo num
  1392.         mov     bl,[2*esi]              ; take byte from source
  1393.         add     ebp,ecx                 ; increment sample position fraction
  1394.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1395.         mov     bl,[2*esi+1]            ; take right byte
  1396.         adc     esi,edx                 ; increment sample position whole part
  1397.         add     eax,[4*ebx]             ; add its value
  1398.         add     [edi+4*num],eax         ; add word into buffer
  1399. ENDM
  1400. MixLoop m8stmo, _m8stmo, 64, bp
  1401.  
  1402. PROC    dsmMix8bitStereoMono    _funct
  1403.  
  1404.         test    _cx,_cx                 ; don't mix zero bytes
  1405.     jz    @@done
  1406.  
  1407.         test    bl,bl                   ; first channel?
  1408.         jne     @@notfirst
  1409.  
  1410.         ; This is the first channel - first clear the destination area
  1411.         push    _di _cx
  1412.         xor     eax,eax
  1413.         rep     stosd
  1414.         pop     _cx _di
  1415.  
  1416. @@notfirst:
  1417.         ; Divide volume by two - we'll add the channels together:
  1418.         inc     bh
  1419.         shr     bh,1
  1420.  
  1421.         mov     [mixLoop],offset m8stmo ; not the first channel - add to buf.
  1422.  
  1423.         call    MixMono
  1424.  
  1425. @@done:
  1426.         ret
  1427. ENDP
  1428.  
  1429.  
  1430.  
  1431.  
  1432. ; 8-bit stereo => stereo mixing routine: (32-bit) (S-L-O-W)
  1433. MACRO   _m8stst num
  1434.         mov     bl,[2*esi]              ; take left byte from source
  1435.         add     ebp,[fracIncr]          ; increment sample position fraction
  1436.         mov     cl,[2*esi+1]            ; take right byte from source
  1437.         mov     eax,[4*ebx]             ; take correct value from volume tbl
  1438.         adc     esi,edx                 ; increment sample position whole part
  1439.         add     [edi+8*num],eax         ; add word to left channel
  1440.         mov     eax,[4*ecx]
  1441.         add     [edi+8*num+4],eax       ; add word to right channel
  1442. ENDM
  1443. MixLoop m8stst, _m8stst, 128, bp
  1444.  
  1445. PROC    dsmMix8bitStereoStereo  _funct
  1446.  
  1447. @@ook:
  1448.         test    _cx,_cx                 ; don't mix zero bytes
  1449.     jz    @@done
  1450.  
  1451.         test    bl,bl                   ; first channel?
  1452.         jne     @@notfirst
  1453.  
  1454.         ; This is the first channel - first clear the destination area
  1455.         push    _di _cx
  1456.         shl     ecx,1
  1457.         xor     eax,eax
  1458.         rep     stosd
  1459.         pop     _cx _di
  1460.  
  1461. @@notfirst:
  1462.         ; Mix 8-bit stereo samples to stereo destination:
  1463.         mov     [mixLoop],offset m8stst
  1464.  
  1465.         call    MixStereo
  1466.  
  1467. @@done:
  1468.         ret
  1469. ENDP
  1470.  
  1471.  
  1472.  
  1473. ; 16-bit mono => mono mixing routine: (32-bit) (S-L-O-W)
  1474. MACRO   _m16momo        num
  1475.         mov     bl,[2*esi]
  1476.         add     ebp,ecx                 ; increment sample position fraction
  1477.         mov     eax,[4*ebx]
  1478.         mov     bl,[2*esi+1]
  1479.         adc     esi,edx                 ; increment sample position whole part
  1480.         sar     eax,8
  1481.         xor     bl,80h
  1482.         add     eax,[4*ebx]
  1483.         add     [edi+4*num],eax         ; add word to left channel
  1484. ENDM
  1485. MixLoop m16momo, _m16momo, 64, bp
  1486.  
  1487. PROC    dsmMix16bitMonoMono     _funct
  1488.  
  1489.         test    _cx,_cx                 ; don't mix zero bytes
  1490.     jz    @@done
  1491.  
  1492.         test    bl,bl                   ; first channel?
  1493.         jne     @@notfirst
  1494.  
  1495.         ; This is the first channel - first clear the destination area
  1496.         push    _di _cx
  1497.         xor     eax,eax
  1498.         rep     stosd
  1499.         pop     _cx _di
  1500.  
  1501. @@notfirst:
  1502.         mov     [mixLoop],offset m16momo ; not the first channel - add to buf.
  1503.  
  1504.         call    MixMono
  1505.  
  1506. @@done:
  1507.         ret
  1508. ENDP
  1509.  
  1510.  
  1511.  
  1512. ; 16-bit mono => stereo mixing routine: (32-bit) (S-L-O-W)
  1513. MACRO   _m16most        num
  1514.         mov     bl,[2*esi]
  1515.         add     ebp,[fracIncr]          ; increment sample position fraction
  1516.         mov     eax,[4*ebx]
  1517.         mov     cl,bl
  1518.         mov     bl,[2*esi+1]
  1519.         adc     esi,edx                 ; increment sample position whole part
  1520.         sar     eax,8
  1521.         xor     bl,80h
  1522.         add     eax,[4*ebx]
  1523.         add     [edi+8*num],eax         ; add word to left channel
  1524.         mov     eax,[4*ecx]
  1525.         mov     cl,bl
  1526.         sar     eax,8
  1527.         add     eax,[4*ecx]
  1528.         add     [edi+8*num+4],eax
  1529. ENDM
  1530. MixLoop m16most, _m16most, 128, bp
  1531.  
  1532. PROC    dsmMix16bitMonoStereo   _funct
  1533.  
  1534.         test    _cx,_cx                 ; don't mix zero bytes
  1535.     jz    @@done
  1536.  
  1537.         test    bl,bl                   ; first channel?
  1538.         jne     @@notfirst
  1539.  
  1540.         ; This is the first channel - first clear the destination area
  1541.         push    _di _cx
  1542.         shl     ecx,1
  1543.         xor     eax,eax
  1544.         rep     stosd
  1545.         pop     _cx _di
  1546.  
  1547. @@notfirst:
  1548.         ; Mix 8-bit stereo samples to stereo destination:
  1549.         mov     [mixLoop],offset m16most
  1550.  
  1551.         call    MixStereo
  1552.  
  1553. @@done:
  1554.         ret
  1555. ENDP
  1556.  
  1557.  
  1558.  
  1559. ; 16-bit stereo => mono mixing routine: (32-bit) (S-L-O-W)
  1560. MACRO   _m16stmo        num
  1561.         mov     bl,[4*esi]
  1562.         mov     eax,[4*ebx]
  1563.         mov     bl,[4*esi+2]
  1564.         add     eax,[4*ebx]
  1565.         mov     bl,[4*esi+1]
  1566.         sar     eax,8
  1567.         xor     bl,80h
  1568.         add     eax,[4*ebx]
  1569.         mov     bl,[4*esi+3]
  1570.         xor     bl,80h
  1571.         add     ebp,ecx                 ; increment sample position fraction
  1572.         adc     esi,edx                 ; increment sample position whole part
  1573.         add     eax,[4*ebx]
  1574.         add     [edi+4*num],eax         ; add word to left channel
  1575. ENDM
  1576. MixLoop m16stmo, _m16stmo, 64, bp
  1577.  
  1578. PROC    dsmMix16bitStereoMono   _funct
  1579.  
  1580.         test    _cx,_cx                 ; don't mix zero bytes
  1581.     jz    @@done
  1582.  
  1583.         test    bl,bl                   ; first channel?
  1584.         jne     @@notfirst
  1585.  
  1586.         ; This is the first channel - first clear the destination area
  1587.         push    _di _cx
  1588.         xor     eax,eax
  1589.         rep     stosd
  1590.         pop     _cx _di
  1591.  
  1592. @@notfirst:
  1593.         ; Divide volume by two - we'll add the channels together:
  1594.         inc     bh
  1595.         shr     bh,1
  1596.  
  1597.         mov     [mixLoop],offset m16stmo ; not the first channel - add to buf.
  1598.  
  1599.         call    MixMono
  1600.  
  1601. @@done:
  1602.         ret
  1603. ENDP
  1604.  
  1605.  
  1606.  
  1607. ; 16-bit stereo => stereo mixing routine: (32-bit) (S-L-O-W)
  1608. MACRO   _m16stst        num
  1609.         mov     bl,[4*esi]
  1610.         mov     eax,[4*ebx]
  1611.         mov     bl,[4*esi+1]
  1612.         sar     eax,8
  1613.         xor     bl,80h
  1614.         add     eax,[4*ebx]
  1615.         add     [edi+8*num],eax         ; add word to left channel
  1616.         mov     cl,[4*esi+2]
  1617.         mov     eax,[4*ecx]
  1618.         mov     cl,[4*esi+3]
  1619.         sar     eax,8
  1620.         xor     cl,80h
  1621.         add     ebp,[fracIncr]          ; increment sample position fraction
  1622.         adc     esi,edx                 ; increment sample position whole part
  1623.         add     eax,[4*ecx]
  1624.         add     [edi+8*num+4],eax
  1625. ENDM
  1626. MixLoop m16stst, _m16stst, 128, bp
  1627.  
  1628. PROC    dsmMix16bitStereoStereo _funct
  1629.  
  1630.         test    _cx,_cx                 ; don't mix zero bytes
  1631.     jz    @@done
  1632.  
  1633.         test    bl,bl                   ; first channel?
  1634.         jne     @@notfirst
  1635.  
  1636.         ; This is the first channel - first clear the destination area
  1637.         push    _di _cx
  1638.         shl     ecx,1
  1639.         xor     eax,eax
  1640.         rep     stosd
  1641.         pop     _cx _di
  1642.  
  1643. @@notfirst:
  1644.         ; Mix 8-bit stereo samples to stereo destination:
  1645.         mov     [mixLoop],offset m16stst
  1646.  
  1647.         call    MixStereo
  1648.  
  1649. @@done:
  1650.         ret
  1651. ENDP
  1652.  
  1653.  
  1654.  
  1655. ;/***************************************************************************\
  1656. ;*
  1657. ;* Function:    int dsmClearBuffer(unsigned numElems)
  1658. ;*
  1659. ;* Description: Clears the mixing buffer. Used only by dsmMixData().
  1660. ;*
  1661. ;* Input:       unsigned numElems       number of elements to clear
  1662. ;*
  1663. ;* Returns:     MIDAS error code.
  1664. ;*
  1665. ;\***************************************************************************/
  1666.  
  1667. PROC    dsmClearBuffer  _funct          numElems : _int
  1668. USES    _si,_di,_bx
  1669.  
  1670.         PUSHSEGREG ds
  1671.  
  1672.         LOADPTR ds,_di,[dsmMixBuffer]   ; point es:di to mixing buffer
  1673.         mov     _cx,[numElems]          ; number of elements
  1674.  
  1675.         call    Clear
  1676.  
  1677.         POPSEGREG ds
  1678.  
  1679.         xor     _ax,_ax
  1680.  
  1681.         ret
  1682. ENDP
  1683.  
  1684.  
  1685.  
  1686.  
  1687. ;/***************************************************************************\
  1688. ;*
  1689. ;* Function:    Clear
  1690. ;*
  1691. ;* Description: Clears part of the mixing buffer
  1692. ;*
  1693. ;* Input:       _di                     Points to mixing buffer position
  1694. ;*              _cx                     Number of elements to clear
  1695. ;*
  1696. ;* Returns:     _di                     New mixing buffer position
  1697. ;*
  1698. ;* Destroys:    eax, _bx, _cx, _di
  1699. ;*
  1700. ;\***************************************************************************/
  1701.  
  1702. PROC    Clear   NEAR
  1703.  
  1704.         ; FIXME - doesn't work with new fast stereo mixing
  1705.  
  1706.         PUSHSEGREG es
  1707.  
  1708.         test    _cx,_cx
  1709.         jz      @@done
  1710.  
  1711.         mov     ax,ds
  1712.         mov     es,ax
  1713.  
  1714.         xor     eax,eax
  1715.         cld
  1716.  
  1717.         cmp     [dsmMode],dsmMixStereo  ; stereo mixing?
  1718.         jne     @@mono
  1719.  
  1720.         shl     _cx,1                   ; twice the number of bytes
  1721.  
  1722. @@mono:
  1723. IFDEF __16__
  1724.         test    di,2                    ; aligned to a dword boundary?
  1725.         jz      @@dword
  1726.         mov     [es:di],ax              ; nope, write one word
  1727.         add     di,2
  1728.         dec     cx
  1729.         jz      @@done
  1730. @@dword:
  1731.         mov     bx,cx
  1732.         shr     cx,1
  1733.         rep     stosd                   ; fill all dwords
  1734.         test    bx,1                    ; still one word to fill?
  1735.         jz      @@done
  1736.         mov     [es:di],ax
  1737.         add     di,2
  1738. ELSE
  1739.         rep     stosd
  1740. ENDIF
  1741. @@done:
  1742.         POPSEGREG es
  1743.  
  1744.         ret
  1745. ENDP
  1746.  
  1747.  
  1748.  
  1749. ;* $Log: dsmmix.asm,v $
  1750. ;* Revision 1.9  1997/01/16 18:41:59  pekangas
  1751. ;* Changed copyright messages to Housemarque
  1752. ;*
  1753. ;* Revision 1.8  1997/01/16 18:19:10  pekangas
  1754. ;* Added support for setting the stream write position.
  1755. ;* Stream data is no longer played past the write position
  1756. ;*
  1757. ;* Revision 1.7  1996/08/02 17:50:24  pekangas
  1758. ;* Changed calls to pointer to go through eax to prevent GNU asm confusion
  1759. ;*
  1760. ;* Revision 1.6  1996/07/13 17:28:10  pekangas
  1761. ;* Fixed to preserve ebx always
  1762. ;*
  1763. ;* Revision 1.5  1996/06/26 19:15:24  pekangas
  1764. ;* Added sample loop callbacks
  1765. ;*
  1766. ;* Revision 1.4  1996/05/30 21:25:48  pekangas
  1767. ;* Fixed a small bug in 16-bit stereo mixing routines
  1768. ;*
  1769. ;* Revision 1.3  1996/05/28 20:30:52  pekangas
  1770. ;* Added mixing routines for 8-bit stereo and 16-bit samples
  1771. ;*
  1772. ;* Revision 1.2  1996/05/23 20:59:08  pekangas
  1773. ;* Removed some DD 0FFFFFFFFh - lines to keep wdisasm from getting confused
  1774. ;*
  1775. ;* Revision 1.1  1996/05/22 20:49:33  pekangas
  1776. ;* Initial revision
  1777. ;*
  1778.  
  1779.  
  1780. END